﻿''' <summary>
''' The primary GdiGaming API control responsible for drawing the game and monitoring input.
''' </summary>
''' <remarks></remarks>
Public Class RenderCanvas
    Protected Friend _Engine As GameEngine

    Private _Buffer1 As Image
    Private _Buffer2 As Image
    Private _BufferFlag As Boolean
    Private _LostBuffers As New System.Collections.Concurrent.ConcurrentQueue(Of Image)

    Public Sub New()
        ' This call is required by the designer.
        InitializeComponent()
        ' Add any initialization after the InitializeComponent() call.
        DoubleBuffered = True
        Size = New Size(640, 480)
        BackColor = Color.CornflowerBlue
    End Sub

    Protected Overrides Function IsInputKey(keyData As System.Windows.Forms.Keys) As Boolean
        Return True
    End Function

    Protected Overrides Sub OnKeyDown(ByVal e As System.Windows.Forms.KeyEventArgs)
        MyBase.OnKeyDown(e)
        If _Engine IsNot Nothing Then
            _Engine.Input._ActiveKeyboardState.SetKey(e.KeyCode, True)
        End If
    End Sub

    Protected Overrides Sub OnKeyUp(ByVal e As System.Windows.Forms.KeyEventArgs)
        MyBase.OnKeyUp(e)
        If _Engine IsNot Nothing Then
            _Engine.Input._ActiveKeyboardState.SetKey(e.KeyCode, False)
        End If
    End Sub

    Protected Overrides Sub OnMouseDown(ByVal e As System.Windows.Forms.MouseEventArgs)
        MyBase.OnMouseDown(e)
        If _Engine IsNot Nothing Then
            _Engine.Input._ActiveMouseState.SetButton(e.Button, True)
        End If
    End Sub

    Protected Overrides Sub OnMouseMove(ByVal e As System.Windows.Forms.MouseEventArgs)
        MyBase.OnMouseMove(e)
        If _Engine IsNot Nothing Then
            _Engine.Input._ActiveMouseState.SetLocation(e.Location)
        End If
    End Sub

    Protected Overrides Sub OnMouseUp(ByVal e As System.Windows.Forms.MouseEventArgs)
        MyBase.OnMouseUp(e)
        If _Engine IsNot Nothing Then
            _Engine.Input._ActiveMouseState.SetButton(e.Button, False)
        End If
    End Sub

    Protected Overrides Sub OnPaint(ByVal e As System.Windows.Forms.PaintEventArgs)
        MyBase.OnPaint(e)
        'Add your custom paint code here
        e.Graphics.DrawImageUnscaled(GetDisplayBuffer, Point.Empty)
    End Sub

    ''' <summary>
    ''' Gets the current buffer image to use for drawing the next frame.
    ''' </summary>
    ''' <returns>The bitmap on which to draw the next frame.</returns>
    ''' <remarks></remarks>
    Public Function GetDrawBuffer() As Image
        If _BufferFlag Then
            Return _Buffer1
        Else
            Return _Buffer2
        End If
    End Function

    ''' <summary>
    ''' Gets the current buffer image being drawn to the screen for the current frame.
    ''' </summary>
    ''' <returns>The bitmap to draw to the screen for the current frame.</returns>
    ''' <remarks></remarks>
    Public Function GetDisplayBuffer() As Image
        If _BufferFlag Then
            Return _Buffer2
        Else
            Return _Buffer1
        End If
    End Function

    ''' <summary>
    ''' Updates the game display by swapping buffers and drawing the new display buffer.
    ''' </summary>
    ''' <remarks></remarks>
    Public Sub UpdateFrame()
        _BufferFlag = Not _BufferFlag
        Invalidate()
        While _LostBuffers.Count > 0
            Dim buffer As Image = Nothing
            If _LostBuffers.TryDequeue(buffer) Then
                buffer.Dispose()
            End If
        End While
    End Sub

    Protected Overrides Sub OnSizeChanged(e As System.EventArgs)
        MyBase.OnSizeChanged(e)
        If _Buffer1 IsNot Nothing Then
            SyncLock _Buffer1
                _LostBuffers.Enqueue(_Buffer1)
                _Buffer1 = GetNewBufferImage()
            End SyncLock
        Else
            _Buffer1 = GetNewBufferImage()
        End If
        If _Buffer2 IsNot Nothing Then
            SyncLock _Buffer2
                _LostBuffers.Enqueue(_Buffer2)
                _Buffer2 = GetNewBufferImage()
            End SyncLock
        Else
            _Buffer2 = GetNewBufferImage()
        End If
    End Sub

    Private Function GetNewBufferImage() As Image
        Return New Bitmap(DisplayRectangle.Width, DisplayRectangle.Height, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
    End Function
End Class

